/* xxx.txt
cmd_count
5
devno,data_type,cmd_size,param,cmd1,cmd2,...
0,0x29,0x0004,0x0000,0x01,0x02,0x03,0x04,
0,0x29,0x0006,0x0000,0x01,0x02,0x03,0x04,0x36,0x45,0x08,0x10,
0,0x15,0x0000,0xedcf,
0,0x15,0x0000,0x0011,
0,0x15,0x0000,0x0029,
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <malloc.h>

#ifndef SIZE_4
#define SIZE_4 4
#endif
#ifndef SIZE_5
#define SIZE_5 5
#endif
#ifndef SIZE_16
#define SIZE_16 16
#endif
#define SAMPLE_CMD_SIZE_LENGTH_MAX 6
#define SAMPLE_CMD_BASE_INFO_LENGTH 21
#define SAMPLE_CMD_INFO_LINE_LENGTH_MAX 1024
#define TD_SUCCESS 0
#define TD_FAILURE -1

typedef struct {
    int devno;
    bool is_hs;
    bool lp_clk_en;
    unsigned char data_type;
    unsigned int cmd_size;
    unsigned char *cmd;
} dsi_cmd_info;


static void print_cmd_info(dsi_cmd_info* info)
{
    unsigned int i;

    printf("----------------------------------------\n");
    printf("devno: %u\n", info->devno);
    printf("data_type: %u\n", info->data_type);
    if (info->cmd == NULL) {
        printf("cmd_param: %#x\n", info->cmd_size);
        return;
    }
    printf("cmd_size: %u\n", info->cmd_size);
    printf("cmd_info:\n\t");
    for (i = 0; i < info->cmd_size; i++) {
        printf("%#x, ", info->cmd[i]);
    }
    printf("\n");
    printf("----------------------------------------\n");
}

static void sample_get_link_info(dsi_cmd_info* cmd_info, char* line, unsigned int line_size)
{
    char devno[2] = { 0 }; /* 2: num and \0 */

    devno[0] = line[0];
    cmd_info->devno = atoi(devno);
    cmd_info->is_hs = true;
    cmd_info->lp_clk_en = true; /* enable: output hs_clk */
}

static void sample_get_data_type(dsi_cmd_info* cmd_info, char* line, unsigned int line_size)
{
    unsigned int i;
    char num_8bit[SIZE_5] = { 0 }; /* 5: cmd and \0 */
    char* endptr = NULL;

    for (i = 0; i < SIZE_4; i++) {
        num_8bit[i] = line[i + 2]; /* 2: data_type location start */
    }

    cmd_info->data_type = (unsigned char)strtol(num_8bit, &endptr, SIZE_16);
}

static unsigned int sample_get_cmd_size(char* line, unsigned int line_size)
{
    unsigned int i;
    char cmd_size[SAMPLE_CMD_SIZE_LENGTH_MAX + 1] = { 0 }; /* 1: \0 */
    char *endptr = NULL;
    unsigned int ret;

    for (i = 0; i < SAMPLE_CMD_SIZE_LENGTH_MAX; i++) {
        cmd_size[i] = line[i + 7]; /* 7: cmd_size location start */
    }

    ret = strtol(cmd_size, &endptr, SIZE_16);

    return ret;
}

static void sample_send_short_pkt(dsi_cmd_info* cmd_info, char* line, unsigned int line_size)
{
    unsigned int i;
    char cmd_size[SAMPLE_CMD_SIZE_LENGTH_MAX + 1] = { 0 }; /* 1: \0 */
    char* endptr = NULL;

    for (i = 0; i < SAMPLE_CMD_SIZE_LENGTH_MAX; i++) {
        cmd_size[i] = line[i + 14]; /* 14: param location start */
    }

    cmd_info->cmd_size = strtol(cmd_size, &endptr, SIZE_16);
    cmd_info->cmd = NULL;
    /* send cmd */
    print_cmd_info(cmd_info);
    if (cmd_info->cmd_size == 0x11 || cmd_info->cmd_size == 0x29) {
        usleep(12000); /* 12000 us */
    }
    else {
        usleep(50); /* 50 us */
    }
}

static void sample_get_cmd_detail(dsi_cmd_info *cmd_info, unsigned int line_id, char *line, unsigned int line_size)
{
    /*
     * if cmd_size > actual_cmd_size;
     * line_size set strlen(line), not send 0x0;
     * line_size set SAMPLE_CMD_SIZE_LENGTH_MAX, send 0x0;
     */
    unsigned int i;
    unsigned int j;
    unsigned int k;
    char num_8bit[SIZE_5] = { 0 }; /* 5: cmd and \0 */
    char* endptr = NULL;

    cmd_info->cmd = (unsigned char*)malloc(sizeof(unsigned char) * cmd_info->cmd_size);
    if (cmd_info->cmd == NULL) {
        printf("err: line[%u], cmd malloc fail!\n", line_id);
        return;
    }
    
    for (i = 0; i < cmd_info->cmd_size; i++) {
        /* if cmd_size > actual_cmd_size, then send 0x00 */
        for (j = 0; j < SIZE_4; j++) {
            k = i * SIZE_5 + SAMPLE_CMD_BASE_INFO_LENGTH + j;
            if (k >= line_size) {
                printf("err: line[%u] length is too long, max:%u\n", line_id, line_size);
                free(cmd_info->cmd);
                return;
            }
            num_8bit[j] = line[k];
        }
        cmd_info->cmd[i] = (unsigned char)strtol(num_8bit, &endptr, SIZE_16);
    }

    /* send cmd */
    print_cmd_info(cmd_info);
    usleep(50); /* 50 us */
    free(cmd_info->cmd);
}

int sample_init_screen_by_user_file(void)
{
    int ret;
    unsigned int i;
    unsigned int line_len;
    char line[SAMPLE_CMD_INFO_LINE_LENGTH_MAX];
    FILE* fp;
    unsigned int cmd_count;
    dsi_cmd_info cmd_info = { 0 };

    ret = fopen_s(&fp, "./xxx.txt", "r");
    if (fp == NULL) {
        printf("Error opening file");
        return TD_FAILURE;
    }

    /* get cmd_count */
    for (int i = 0; i < 3; i++) { /* 3: line */
        (void)memset_s(line, SAMPLE_CMD_INFO_LINE_LENGTH_MAX, 0, SAMPLE_CMD_INFO_LINE_LENGTH_MAX);
        //(void)memset(line, 0, sizeof(line));
        if (fgets(line, SAMPLE_CMD_INFO_LINE_LENGTH_MAX, fp) == NULL) {
            printf("Error reading file");
            break;
        }
        if (i == 0 || i == 2) { /* 0, 2: not read line info */
            continue;
        }
        cmd_count = atoi(line);
        if (cmd_count == 0) {
            printf("line[%u], cmd count is 0, not send cmd\n", i);
            goto end_flag;
        }
    }

    /* get cmd */
    for (i = 0; i < cmd_count; i++) {
        (void)memset_s(line, SAMPLE_CMD_INFO_LINE_LENGTH_MAX, 0, SAMPLE_CMD_INFO_LINE_LENGTH_MAX);
        //(void)memset(line, 0, sizeof(line));
        if (fgets(line, SAMPLE_CMD_INFO_LINE_LENGTH_MAX, fp) == NULL) {
            printf("Error reading line(%u)\n", i);
            break;
        }
        line_len = strlen(line);
        if (line_len < SAMPLE_CMD_BASE_INFO_LENGTH) {
            printf("Error reading line(%u), cmd incorrect\n", i);
        }

        sample_get_link_info(&cmd_info, line, line_len);
        sample_get_data_type(&cmd_info, line, line_len);
        cmd_info.cmd_size = sample_get_cmd_size(line, line_len);
        if (cmd_info.cmd_size == 0) {
            sample_send_short_pkt(&cmd_info, line, line_len);
            continue;
        }

        sample_get_cmd_detail(&cmd_info, i, line, line_len);
    }

end_flag:
    fclose(fp);
    return TD_SUCCESS;
}

int main() {
    sample_init_screen_by_user_file();
    return 0;
}
